#!/usr/bin/env python2
#-*- coding: utf-8 -*-


import datetime
import traceback
import functools
import urlparse
import logging

from urllib import urlencode
from flask import Flask
from sqlalchemy import exc as sql_exc


from Ump.common import exception
from Ump.common.utils import inspect_func
from Ump.objs.db import config as db_config
from Ump.objs.db.models import db

from jsonify import data2json


LOG = logging.getLogger('Ump.webutil')


class HTTPError(Exception):
    """An exception that will turn into an HTTP error response.

    Raising an `HTTPError` is a convenient alternative to calling
    `RequestHandler.send_error` since it automatically ends the
    current function.

    To customize the response sent with an `HTTPError`, override
    `RequestHandler.write_error`.

    :arg int status_code: HTTP status code.  Must be listed in
        `httplib.responses <http.client.responses>` unless the ``reason``
        keyword argument is given.
    :arg string log_message: Message to be written to the log for this error
        (will not be shown to the user unless the `Application` is in debug
        mode).  May contain ``%s``-style placeholders, which will be filled
        in with remaining positional parameters.
    :arg string reason: Keyword-only argument.  The HTTP "reason" phrase
        to pass in the status line along with ``status_code``.  Normally
        determined automatically from ``status_code``, but can be used
        to use a non-standard numeric code.
    """
    def __init__(self, status_code=500, log_message=None, *args, **kwargs):
        self.status_code = status_code
        self.log_message = log_message
        self.args = args
        self.reason = kwargs.get('reason', None)
        if log_message and not args:
            self.log_message = log_message.replace('%', '%%')

    def __str__(self):
        message = "HTTP %d: %s" % (self.status_code, self.reason)
        if self.log_message:
            return message + " (" + (self.log_message % self.args) + ")"
        else:
            return message


def authenticated(auth=True):
    def decorator(method):
        """Decorate methods with this to require that the user be logged in.

        If the user is not logged in, they will be redirected to the configured
        `login url <RequestHandler.get_login_url>`.

        If you configure a login url with a query parameter, Tornado will
        assume you know what you're doing and use it as-is.  If not, it
        will add a `next` parameter so the login page knows where to send
        you once you're logged in.
        """
        @functools.wraps(method)
        def wrapper(self, *args, **kwargs):
            try:

                # TODO can't reconnect until invalid transaction is rolled back.
                if auth and not self.current_user():
                    print "none none none"
                    return exception2json('没有认证信息', status='401 Unauthorized')

                res = method(self, *args, **kwargs)
                return res
#                    res = method(self, *args, **kwargs)
#                    return res
            except exception.InvalidParameter, e:
                traceback.print_exc()
                return exception2json(e, status='400 Bad Request')
            except exception.TokenExpire, e:
                traceback.print_exc()
                return exception2json(e, status='401 Unauthorized')
            except exception.NotFound, e:
                traceback.print_exc()
                return exception2json(e, status='404 Not Found')
            except sql_exc.InvalidRequestError, e:
                # TODO
                traceback.print_exc()
                return exception2json(e, status='500')
            except Exception, e:
                traceback.print_exc()
                return exception2json(e, status='500')
        return wrapper
    return decorator


def requesthandler(method):
    @functools.wraps(method)
    def wrapper(self, *args, **kwargs):
        try:
            res = method(self, *args, **kwargs)
            return res
        except exception.InvalidParameter, e:
            traceback.print_exc()
            return exception2json(e, status='400 Bad Request')
        except exception.TokenExpire, e:
            traceback.print_exc()
            return exception2json(e, status='401 Unauthorized')
        except exception.NotFound, e:
            traceback.print_exc()
            return exception2json(e, status='404 Not Found')
        except Exception, e:
            traceback.print_exc()
            return exception2json(e, status='500')
    return wrapper


@inspect_func
def success2json(records):
    # records = object2dict(records)

    if isinstance(records, list):
        count = len(records)
    else:
        count = 1

    data = {
        "reply": {
            "is_success": True,
            "error":"",
            'count': count,
        },
        'records': records
    }
    return data2json(data), 200


@inspect_func
def exception2json(error, status='500'):
    '''return program error to ui,format is json '''
    #if isinstance(error, Exception):
    #    msg = '%s: %s' % (error.__class__.__name__, error)
    msg = '%s' % (error)
    data =  {
        "reply": {
            "is_success": False,
            "error": msg,
        }
    }
    return data2json(data), status


def web_return(func, *args, **kwargs):
    kwargs.pop('skip2dict', False)

    # print '--- func', func, args, kwargs
    resultObj = func(*args, **kwargs)

    LOG.info('--- web_return')
    LOG.info('%s %s %s %s' % (func, args, kwargs, resultObj))

    if resultObj is None:
        raise exception.NotFound(*args, **kwargs)

    return success2json(resultObj)


def ui_return(func, *args, **kwargs):
    try:
        resultObj = func(*args, **kwargs)
        if resultObj is None:
            resultObj = True
        return success2json(resultObj)
    except Exception, e:
        traceback.print_exc()
        return exception2json(e)


# def init_flask_app(SQLALCHEMY_DATABASE_URI=None):
#     app = Flask(__name__)
#     app.config['SECRET_KEY'] = 'dfasfafadsfasf'
#     app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI or db_config.sqlalchemy_database_uri()
#     app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#     db.init_app(app)
#     return app, db
